/*
 *	OpenSource code and fragments by avocado systems, Marcus Fuhrmeister
 *
 *	Redistribution and use in source and binary forms, with or without
 *	modification, are permitted provided that the following conditions
 *	are met:
 *  
 *		* Redistribution of source code must retain the above OpenSource comment,
 *		this list of conditions and the following disclaimer.
 * 
 *		* Redistribution in binary form must reproduce the above OpenSource comment,
 *		this list of conditions and the following disclaimer in the
 *		documentation and/or other materials provided with the distribution.
 * 
 *	Neither the name of 'avocaod systems, Marcus Fuhrmeister' or the
 *	names of contributors may be used to endorse or promote products derived
 *	from this software without specific prior written permission.
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 */
package de.fuhrmeister.browserchooser;

import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Window;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;

import de.fuhrmeister.util.ImageManager;

/**
 * Creates a splash image while loading the class with the actual main method.
 * 
 *	@date		24.08.2010
 *	@author		Marcus Fuhrmeister
 */
public class SplashLoader extends Window {
	
	private static final long serialVersionUID = 7530640193608531730L;
	private boolean paintCalled = false;
	private Image splashImage;

	/**
	 * Sets or creates a new splash image, loads it and inits the bounds of this window.
	 * 
	 * @param owner the owner frame
	 * @param splashImage the splash image
	 */
	public SplashLoader(final Frame owner, Image splashImage) {
		super(owner);
		if (splashImage != null) {
			this.splashImage = splashImage;
		} else {
			final BufferedImage bfImage = new BufferedImage(100, 100, 1);
			final Graphics g = bfImage.getGraphics();
			g.setColor(java.awt.Color.RED);
			g.drawLine(0, 0, 100, 100);
			g.drawLine(0, 99, 99, 0);
			splashImage = bfImage;
			this.splashImage = bfImage;
		}

		final MediaTracker mt = new MediaTracker(this);
		mt.addImage(splashImage, 0);
		try {
			mt.waitForID(0);
		} catch (final InterruptedException ex) {
			ex.printStackTrace();
		}

		setSize(splashImage.getWidth(this), splashImage.getHeight(this));
		setLocationRelativeTo(null);

		final MouseAdapter disposeOnClick = new MouseAdapter() {
			@Override
			public void mouseClicked(final MouseEvent evt) {
				// Note: To avoid that method splash hangs, we
				// must set paintCalled to true and call notifyAll.
				// This is necessary because the mouse click may
				// occur before the contents of the window
				// has been painted.
				synchronized (SplashLoader.this) {
					SplashLoader.this.paintCalled = true;
					SplashLoader.this.notifyAll();
				}
				dispose();
			}
		};
		addMouseListener(disposeOnClick);
	}

	/**
	 * Prevents flickering.
	 */
	@Override
	public void update(final Graphics g) {
		// Note: Since the paint method is going to draw an
		// image that covers the complete area of the component we
		// do not fill the component with its background color
		// here. This avoids flickering.
		g.setColor(getForeground());
		paint(g);
	}

	/**
	 * Draws the splash image.
	 */
	@Override
	public void paint(final Graphics g) {
		g.drawImage(splashImage, 0, 0, this);
		// Notify method splash that the window
		// has been painted.
		if (!paintCalled) {
			paintCalled = true;
			synchronized (this) {
				notifyAll();
			}
		}
	}

	/**
	 * Creates the splash image component and waits until it has been drawn.
	 * 
	 * @param splashImage the splash image
	 * @return the parent frame
	 */
	public static Frame splash(final Image splashImage) {
		final Frame f = new Frame();
		final SplashLoader w = new SplashLoader(f, splashImage);
		w.toFront();
		w.setVisible(true);

		// Note: To make sure the user gets a chance to see the
		// splash window we wait until its paint method has been
		// called at least once by the AWT event dispatcher thread.
		if (!EventQueue.isDispatchThread()) {
			synchronized (w) {
				while (!w.paintCalled) {
					try {
						w.wait();
					} catch (final InterruptedException e) {
					}
				}
			}
		}
		return f;
	}

	/**
	 * Entry point showing a splash image until the application's main class has loaded.
	 * 
	 * @param args
	 */
	public static void main(final String[] args) {
		Frame splashFrame = null;
		splashFrame = splash(ImageManager.getInstance().getImage(ImageManager.SPLASH));
		try {
			Class.forName("de.fuhrmeister.browserchooser.Loader").getMethod("main", new Class[] { String[].class }).invoke(null, new Object[] { args });
		} catch (final Exception ex) {
			ex.printStackTrace();
			System.exit(10);
		}
		if (splashFrame != null) {
			splashFrame.dispose();
		}
	}
}